home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
asmbler.arc
/
DESEQ.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-11-19
|
15KB
|
398 lines
COMMENT \
Filter TOPS-20 sequence numbers from the standard input file. These
consist of sequences nnnn<Bn><09> at the beginning of each line. That
is, the fifth character is a digit <3n> which has been OR'ed with <80>.
This is how Kermit flags the fifth character from a DEC-20 36-bit word
in which the rightmost bit is 1. Trailing blanks are also trimmed. If
any single line is longer than the internal line buffer size (256), it
will be output unprocessed and a warning message will be issued. This
should be rare, and if the number of occurrences is small, hand editing
of the output file could fix the problem.
Usage: deseq <inputfile >outputfile
Error return codes:
0 - normal termination
1 - write error on standard output file (usually because disk full);
an error message is printed.
{Adapted from a disassembly of the IBM utility MORE.COM and commented
with a view to being a model for further simple filters.}
For efficiency, input and output characters are handled in large buffers.
[28-Jan-84]
\
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
deseqc segment para public 'code'
include dos.inc
include ascii.inc
org 100h ; this is a .COM file
DEBUG equ 0 ; non-zero for built-in input file test
; Sum of buffer sizes can be 64K-(code + otherdata size), or about 40K total
MAXOUTBUF equ 16384 ; Output buffer size
MAXINBUF equ 16384 ; Input buffer size
MAXLINBUF equ 256 ; Line buffer size
deseq proc near
call check_dos_version
if DEBUG
mov dx,offset debugfn
mov al,$DOS_OPEN2_READ
mov ah,$DOS_OPEN2
int $DOS
jnc openok
int $HALT ; open failure
openok:
mov debugin,ax ; save file handle
endif
mov inbuf_prev,0 ; set empty input buffer
mov inbuf_len,0 ; set empty input buffer
mov linbuf_len,0 ; set empty line buffer
mov outbuf_len,0 ; set empty output buffer
readln:
call get_line ; get an input line
mov cx,linbuf_len ; Get output line length
jcxz eof ; No more data, all done
call strip_line ; Yes, go strip any line number
putlin:
call trim_line
call write_line ; go write the line
jmp short readln ; Loop for next line
eof: ; here at end-of-file
call write_buf ; write any remaining data
mov ah,$DOS_EXIT ; all done, no more data
mov al,0 ; return code
int $DOS ; terminate
if DEBUG
even ; align on word boundary
debugin dw ?
debugfn db "c:\pascal\foo.for",.NUL
endif
even ; align on word boundary
inbuf_prev dw ? ; Buffer pointer
inbuf_len dw ? ; Buffer size
inbuf db MAXINBUF dup (?) ; Input buffer
even ; align on word boundary
linbuf_len dw ? ; Buffer pointer
linbuf db MAXLINBUF dup (?) ; Output buffer for line storage
even ; align on word boundary
outbuf_len dw ? ; Buffer length
outbuf db MAXOUTBUF dup (?) ; Output buffer for final write
deseq endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
trim_line proc near
; Routine to trim trailing white space from line. No action is taken if
; the line buffer does not end with CR LF, since in that case, the line
; is incomplete (long line split across buffer boundary).
; No registers are preserved
mov cx,linbuf_len ; line length
mov si,offset linbuf-3 ; output buffer address-3
add si,cx ; address of last character before CR LF
mov al,[si+1] ; get what should be CR
cmp al,.CR ; was it?
jne notrim ; no, not really end-of-line
mov al,[si+2] ; get what should be LF
cmp al,.LF ; was it?
jne notrim ; no, not really end-of-line
std ; set direction flag to decrement si
trim:
lodsb ; byte from [si] to al, decrement si
cmp al," " ; blank?
je zap_space ; yes
cmp al,.HT ; tab?
jne notrim ; no, not white space, so exit loop
zap_space:
mov byte ptr [si+1],.NUL ; change blank or tab to NUL
loop trim ; decrement cx and loop until cx = 0
notrim:
ret ; return to caller
trim_line endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
strip_line proc near
; Routine to strip line numbers
; No registers are preserved
mov cx,linbuf_len ; line length
cmp cx,8 ; Possible nnnnn<TAB> .. <CR><LF> on this line?
jle strip_done ; No, return immediately
mov si,offset linbuf; line buffer address
cld ; clear direction flag to increment si
nextch: ; Loop looking for line numbers
lodsb ; Byte from [si] to al, increment si
cmp al,128 ; 8-th bit on?
jb ordchr ; Jump if not
call check_seq ; Check for sequence number and clear if so
ordchr: ; Ordinary character
loop nextch ; Decrement count in cx and loop until cx = 0
strip_done:
ret ; return to caller
strip_line endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
get_line proc near
; Routine to get a line from the standard input file, leaving it
; in line_buf with its length in line_len. line_len will be zero
; on end-of-file.
; no registers preserved
getnext:
call getch ; get next input character
jz eol ; zero when no more input
push ax ; save character
call write ; save in line buffer
pop ax ; restore character
cmp al,.LF ; end-of-line yet?
jne getnext ; jump if not LF
eol: ; here on eol or possibly eof
ret ; return to caller
get_line endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
check_dos_version proc near
; Routine to check for DOS version 2.00 or later. Aborts with message
; if not so.
; No registers preserved
mov ah,$DOS_GETVERSION
int $DOS
xchg ah,al
cmp ax,0200h ; DOS 2.00 or later?
jnb cont ; jump if version >= 2.00
mov dx,offset baddos
mov ah,$DOS_STROUT
int $DOS ; print string to standard output
int $HALT ; terminate early version of DOS
cont:
ret
baddos db "DESEQ: Incorrect DOS version"
db " -- must run under DOS 2.00 or later"
db .CR,.LF,"$"
check_dos_version endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
getch proc near
; Routine to get next character from standard input in al.
; Returns with zero flag set on end-of-file, clear otherwise
; No registers are preserved
mov bp,inbuf_prev ; Pointer to next available byte in buffer
cmp bp,inbuf_len ; Bytes left in buffer?
jl noread ; Yes, no need to read more yet
mov ah,$DOS_READ2 ; string read code
if DEBUG
mov bx,debugin ; file handle
else
mov bx,$STDIN ; file handle
endif
mov cx,MAXINBUF ; count of bytes to read
mov dx,offset inbuf ; buffer address
int $DOS ; read a block of characters
mov inbuf_len,ax ; number of bytes actually read
mov inbuf_prev,0 ; Point to last byte returned
or ax,ax ; test number of bytes obtained
jz done ; return with zero flag set on EOF
noread:
mov bp,inbuf_prev ; offset of next character available
mov al,inbuf[bp] ; get the character from the buffer
inc inbuf_prev ; increment byte pointer (and set condition
; flag to non-zero)
done:
ret ; return to caller with zero/non-zero flag set
getch endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
write proc near
; Routine to write the character in al to the line buffer. If the
; buffer is filled, it is automatically written to the standard
; output file by a call to write_line and an error message is issued
; noting the overflow. Characters are not lost in the output, but
; processing on the current line will not be correct.
; No registers are preserved
mov bp,linbuf_len ; offset of next available slot in buffer
cmp bp,MAXLINBUF ; buffer full yet?
jl nowrite ; no, just add to buffer
push ax ; yes, save character
call write_line ; then write the buffer
push bx ; save registers
push cx
push dx
mov ah,$DOS_WRITE2 ; and write an error message
mov bx,$STDERR
mov cx,linemsg_len
mov dx,offset linemsg
int $DOS
pop dx ; restore registers
pop cx
pop bx
pop ax ; and restore the character
mov bp,0 ; new output buffer length in index register
mov linbuf_len,bp ; and storage
nowrite: ; here with bp pointing to offset of next char
mov linbuf[bp],al ; save the character
inc linbuf_len ; increment output buffer length
ret ; return to caller
linemsg db "%Long line overflows buffer - processing incomplete",.CR,.LF
linemsg_len equ $-linemsg
write endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
write_line proc near
; Routine to write the line buffer to the output buffer. Any NUL's found
; are discarded.
; No registers are preserved.
mov cx,linbuf_len ; current line length
jcxz wrdone ; exit if no characters left to write
mov si,offset linbuf; line buffer address
mov bx,outbuf_len ; old output buffer length
lea di,outbuf[bx] ; address of next available char in output
cld ; clear direction flag to increment si and di
mvbuff: ; copy the buffer discarding NULs
lodsb ; character from [si] to al, increment si
cmp al,.NUL ; NUL?
je mvloop ; yes, skip output
cmp bx,MAXOUTBUF ; still space in output buffer?
jl mvchar ; yes, store the character
call write_buf ; no, empty the buffer
mov bx,outbuf_len ; old output buffer length
mvchar:
stosb ; character from al to [di], increment di
inc bx ; count the character
mvloop:
loop mvbuff ; decrement cx, and loop while cx > 0
wrdone:
mov outbuf_len,bx ; update output buffer length
mov linbuf_len,0 ; indicate empty buffer
ret ; return to caller
write_line endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
write_buf proc near
; Routine to write outbuf buffer to the standard output file.
; All registers are preserved.
; Error returns from DOS (e.g. disk full) result in an error message
; and immediate termination.
push ax ; save registers
push bx
push cx
push dx
mov ah,$DOS_WRITE2
mov bx,$STDOUT ; file handle
mov cx,outbuf_len ; count of bytes to write
jcxz writeok ; exit if nothing to write
mov dx,offset outbuf; buffer address
int $DOS ; write the buffer
jnc writeok
mov ah,$DOS_WRITE2 ; write failed, issue message
mov bx,$STDERR ; file handle
mov cx,writemsg_len ; count
mov dx,offset writemsg ; buffer
int $DOS
mov ah,$DOS_EXIT
mov al,1 ; return code
int $DOS ; abort
writeok:
mov outbuf_len,0 ; show empty buffer
pop dx ; restore registers
pop cx
pop bx
pop ax
ret
writemsg db "?Unrecoverable write error on standard output file",.CR,.LF
db " Disk probably full",.CR,.LF
writemsg_len equ $-writemsg
write_buf endp
assume cs:deseqc,ds:deseqc,es:deseqc,ss:deseqc
check_seq proc near
; Routine to check that we have 5 digits followed by a tab, and if
; so, replace it by NULs. On entry, si points to character FOLLOWING
; one with bit 8 set, and al contains the latter character.
; Preserves all registers
push bx ; save bx
push ax ; and ax
cmp byte ptr [si],.HT ; check for following tab
jne check_done ; jump if not tab
mov bx,-5 ; loop count
check_dig: ; loop testing for digits
mov al,[si+bx] ; get digit
cmp bx,-1 ; digit before tab?
jne no_clear ; jump if not
and al,7FH ; yes, clear high bit - nnnnN<tab>
no_clear:
cmp al,.DIGIT0
jb check_done ; not a digit
cmp al,.DIGIT9 ;
ja check_done ; not a digit
inc bx ; was digit, bx = bx + 1
jl check_dig ; loop until bx = 0
mov byte ptr [si-5],.NUL ; set the nnnnn<TAB> field to NULs
mov byte ptr [si-4],.NUL
mov byte ptr [si-3],.NUL
mov byte ptr [si-2],.NUL
mov byte ptr [si-1],.NUL
mov byte ptr [si],.NUL
check_done:
pop ax ; restore ax
pop bx ; restore bx
ret ; return to caller
check_seq endp
deseqc ends
end deseq